2018_riley_in_c.py

#

SPDX-FileCopyrightText: 2018 Boris Bardonneau & Nestor Beguin SPDX-FileCopyrightText: 2024 AlICe laboratory https://alicelab.be

SPDX-License-Identifier: GPL-3.0-or-later

#

SETUP CAMERA AND MODEL CLEANING# ###go line 100 for code

import bpy
import random
from random import choice

for o in bpy.data.objects:  # nettoie aussi l'animation
    o.hide = False
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete(use_global=False)
#

script realise sous Blender hach 4bb1e22 18.11.2016 par AlICelab CAMERA SCRIPT

import math
from math import radians
from math import cos
from math import sin
#

Definition de la fonction de création de camera en projection parallele

def axoCam(projection, canon):
    bpy.ops.object.camera_add()
    maScene = bpy.context.scene.render
    monAxoCam = bpy.context.object
    monAxoCam.data.type = "ORTHO"
    monAxoCam.data.ortho_scale = 30
    if projection == "axonometrique":
        if canon == "isometrie":  # OK
            monAxoCam.name = "axoIsometrie"
            monAxoCam.rotation_euler = (radians(54.74), 0.0, radians(45))
            monAxoCam.location = (10.0, -10.0, 10.0)
            maScene.pixel_aspect_x = 1
        if canon == "dimetrie":  # OK
            monAxoCam.name = "axoDimetrie"
            monAxoCam.rotation_euler = (radians(60), 0.0, radians(23))
            monAxoCam.location = (5.53, -13.04, 8.18)
            maScene.pixel_aspect_x = 1
        if canon == "trimetrie":  # OK
            monAxoCam.name = "axoTrimetrie"
            monAxoCam.rotation_euler = (radians(67), 0.0, radians(34))
            monAxoCam.location = (8.59, -12.734, 6.52)
            maScene.pixel_aspect_x = 1
    if projection == "oblique":
        if canon == "militaire":  # OK
            monAxoCam.name = "oblMilitaire"
            monAxoCam.rotation_euler = (radians(45), 0.0, radians(30))
            monAxoCam.location = (7.071, -12.247, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45))
        if canon == "militaireDiminuee":  # OK
            monAxoCam.name = "oblMilitaireDiminuee"
            monAxoCam.rotation_euler = (radians(45 * 0.82), 0.0, radians(30))
            monAxoCam.location = (5.309, -9.195, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45 * 0.82))
        if canon == "cavalierePlan":  # OK
            monAxoCam.name = "oblCavalierePlan"
            monAxoCam.rotation_euler = (radians(45), 0.0, radians(45))
            monAxoCam.location = (10.0, -10.0, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45))
        if canon == "cavalierePlanDiminuee":  # OK
            monAxoCam.name = "oblCavalierePlanDiminuee"
            monAxoCam.rotation_euler = (radians(45 * 0.82), 0.0, radians(45))
            monAxoCam.location = (7.5, -7.5, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(radians(45 * 0.82))
        if canon == "cavaliereAngleCam":  # OK mais à recentrer manuellement
            angleZ = radians(30)  # entrer l'angle de rotation de la camera en Z
            angleZ_XY = radians(
                15
            )  # entrer l'angle d'inclinaison de la camera par rapport au sol
            monAxoCam.name = "oblCavalierePlanDiminuee"
            monAxoCam.rotation_euler = (angleZ_XY, 0.0, angleZ)
            monAxoCam.location = (10, -10, 10 * 1 / cos(radians(45)))
            maScene.pixel_aspect_x = 1 / cos(angleZ_XY)
#

Execution de la fonction de création de la camera choix du type de projection: Effacer le # devant la ligne pour choisir le type de camera à créer

#

PROJECTION OBLIQUE#

axoCam (‘oblique’,’militaire’) axoCam (‘oblique’,’militaireDiminuee’) axoCam (‘oblique’,’cavalierePlan’) axoCam (‘oblique’,’cavalierePlanDiminuee’) axoCam (‘oblique’,’cavaliereAngleCam’) #celle ci peut être réglée en angle de vue -> regarder dans la dernière formule

#

PROJECTION AXONOMETRIQUE#

axoCam("axonometrique", "isometrie")
#

axoCam (‘axonometrique’,’dimetrie’) axoCam (‘axonometrique’,’trimetrie’)

#
###########CODE “IN C” DE TERRY RILEY##########################”
#

DIMENSIONEMENT DE L’ENVELOPPE GENERALE ET DU CENTRE DU SOCLE ( CUBE )

Rectanglex = [10]
Rectangley = [10]
Rectangleposx = [5]
Rectangleposy = [5]
#

FONCTIONS

def Division(x, y, px, py, i):  # SEGMENTATION DU SOCLE EN MUSICIENS
    choix = 1 if x > y else 0  # Détermine le plus grand rectangle de la liste
    if choix == 1:  # Segmente en x
        xvar = random.uniform(0, x)
        xvar2 = x - xvar
        yvar = y
        yvar2 = y

        posx = px - x / 2 + xvar / 2
        posy = py

        posx2 = px - x / 2 + xvar + xvar2 / 2
        posy2 = py
    else:  # Segmente en y
        yvar = random.uniform(0, y)
        yvar2 = y - yvar
        xvar = x
        xvar2 = x

        posx = px
        posy = py - y / 2 + yvar / 2

        posx2 = px
        posy2 = py - y / 2 + yvar + yvar2 / 2

    Rectanglex[i] = xvar  # Change la valeur du rectangle de base
    Rectangley[i] = yvar
    Rectangleposx[i] = posx
    Rectangleposy[i] = posy

    Rectanglex.append(xvar2)  # Ajoute le second rectangle créé
    Rectangley.append(yvar2)
    Rectangleposx.append(posx2)
    Rectangleposy.append(posy2)
#
def Phrasemusicale(
    x, y, z, px, py, h, t
):  # Choix des différente formes de base pour définir les phrases musicales

    if t == 0:  # rectangle dimensions 100%
        bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(px, py, z))
        bpy.ops.transform.resize(value=(x, y, h))
    if t == 3:  # rectangle dimensions 100%2 pour plus de ratio
        bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(px, py, z))
        bpy.ops.transform.resize(value=(x, y, h))
    if t == 6:  # cylindre dimension 50%
        bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=1, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 2, y / 2, h))

    if t == 2:  # cylindre dimension 25% et décalé en x+
        bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=1, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 8, y / 8, h))
    if t == 4:  # cylindre dimension 25% et décalé en x-
        bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=1, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 8, y / 8, h))
    if t == 1:  # rectangle dimension 50%
        bpy.ops.mesh.primitive_cube_add(radius=0.5, location=(px, py, z))
        bpy.ops.transform.resize(value=(x / 6, y / 635, h))

    bpy.context.object.name = "Phrase" + str(z)  # nomenclature de la forme
#
############################################ DONNEES
Musiciens = 40  # Nombre de musiciens désirés
Mesures = 40  # Longueur de la chanson
hauteur = 10 / Mesures  # hauteur des phrases
frame_num = 0  # animation
animation_speed = 1  # Vitesse de l'animation(Nombre de frames par niveau)
Temps_video = 20  # temps de la video en seconde
Phrases_Count = 53  # Nombres de phrases musicales
TransMin = 1  # Scale pour phrase musicale minimum
TransMax = 2  # Scale pour phrase musicale maximum
typemax = 4  # nombre de type de formes différentes
sens = True  # sens de départ d'aparitiin
seuilonoff = 5  # seuil% de chance de passer on/off
seuilmin = 30  # nombre de musicien actif max
seuilmax = 90  # nombre de musicien actif min
#

ANIMATION SETTINGS

bpy.context.scene.render.fps = Mesures / Temps_video  # frequence d'encodage
bpy.context.scene.frame_end = Mesures * animation_speed  # Nombre d'image autocalculé
bpy.context.scene.frame_step = animation_speed  # Vitesse d'image autocalculé
#

bpy.ops.mesh.primitive_plane_add(location=(0,0,-4.9)) #Ajout d’un socle pour recevoir les ombres bpy.ops.transform.resize(value= (100,100,0))

bpy.ops.object.lamp_add(
    type="SUN", location=(10, 10, 20)
)  # ajout du soleil et orientation
bpy.ops.transform.rotate(
    value=0.727953,
    axis=(0, 1, 0),
    constraint_axis=(False, True, False),
    constraint_orientation="GLOBAL",
    mirror=False,
    proportional="DISABLED",
    proportional_edit_falloff="SMOOTH",
    proportional_size=1,
    release_confirm=True,
    use_accurate=False,
)
#

bpy.ops.transform.rotate(value=-0.727953, axis=(1, 0, 0), constraint_axis=(True, False, False), constraint_orientation=’GLOBAL’, mirror=False, proportional=’DISABLED’, proportional_edit_falloff=’SMOOTH’, proportional_size=1, release_confirm=True, use_accurate=False)

bpy.context.object.data.shadow_method = "RAY_SHADOW"
#

LISTES

Coordonees = []  # Position des musiciens
Statut = []  # Musiciens actifs, inactifs
Phrases_musicales_taille = []  # Phrases musciales_taille
Phrases_musicales_type = []  # Phrases musciales_type de forme
Phrases_musicales_Index = []  # position du musicien dans la liste des phrases musciales
#

SEGMENTATION DU SOCLE EN MUSICIENS

for i in range(0, Musiciens):

    max_x, max_y = max(Rectanglex), max(Rectangley)

    i = Rectanglex.index(max_x) if max_x > max_y else Rectangley.index(max_y)

    Division(Rectanglex[i], Rectangley[i], Rectangleposx[i], Rectangleposy[i], i)
#

PHRASES MUSICALES

for i in range(
    Phrases_Count
):  # Crée un liste de phrases musicale de différent type et tailles
    Phrases_musicales_taille.append(random.uniform(TransMin, TransMax))
    Phrases_musicales_type.append(random.randint(0, typemax))
#

INDEXATION DES MUSICIENS

for i in range(0, len(Rectanglex)):
    Statut.append(random.randint(0, 1))  # Commence actif ou inactif
    Phrases_musicales_Index.append(1)  # Commence par la 1ere phrase musicale
#

APPLICATION

for z in range(0, Mesures):  # Pour autant de mesures(z)
    print("Mesure", z)
    var1 = Statut.count(1)  # Nombre de musiciens Actifs
    var2 = len(Statut)  # Nombre total de musiciens
    musicienactifs = var1 / var2 * 100  # % de musicien actif
    print(musicienactifs, "%", " actif")
    if musicienactifs < seuilmin:  # passe en mode ascendant
        sens = True
    if musicienactifs > seuilmax:  # passe en mode descendant
        sens = False
    for i in range(0, len(Rectanglex)):  # pour tous les musiciens un par un par étage

        if Statut[i] == 1:  # Si musicien actif
#

s’arrete si musicien a fini les phrases

            if Phrases_musicales_Index[i] == Phrases_Count - 1:
                continue
            else:
#
#########Création d’une forme
                Phrasemusicale(
                    Rectanglex[i],
                    Rectangley[i],
                    z * hauteur - 5,
                    Rectangleposx[i] - 5,
                    Rectangleposy[i] - 5,
                    hauteur,
                    Phrases_musicales_type[Phrases_musicales_Index[i]],
                )
                bpy.ops.transform.resize(
                    value=(
                        Phrases_musicales_taille[Phrases_musicales_Index[i]],
                        Phrases_musicales_taille[Phrases_musicales_Index[i]],
                        1,
                    )
                )
#

DEBUT DE L’ANIMATION

                obj = bpy.context.active_object
#

key as visible on the current frame

                obj.keyframe_insert("hide", frame=z * animation_speed)
                obj.keyframe_insert("hide_render", frame=z * animation_speed)
#

hide it

                obj.hide = True
                obj.hide_render = True
#

key as hidden on the previous frame

                obj.keyframe_insert(
                    "hide", frame=z * animation_speed - 1 * animation_speed
                )
                obj.keyframe_insert(
                    "hide_render", frame=z * animation_speed - 1 * animation_speed
                )
#

key as hidden on the next frame obj.keyframe_insert(‘hide’,frame=z+1) obj.keyframe_insert(‘hide_render’,frame=z+1)

FIN DE L’ANIMATION

        if sens:  # si  ascendant
            if not Statut[i]:
                if random.randint(0, 100) <= seuilonoff:  # % de chance de passer actif
#

print(‘actif’)

                    Statut[i] = 1

        if not sens:
#

si musicien actif

            if Statut[i]:
                if (
                    random.randint(0, 100) <= seuilonoff
                ):  # % de chance de passer inactif
#

print(‘inactif’)

                    Statut[i] = 0
#

ne s’applique pas si le musicien a fini ses phrases

        if Phrases_musicales_Index[i] == Phrases_Count - 1:
            continue
        else:
            if Phrases_musicales_Index[i] >= 5:  # Si musicien au dessus de la 5e phrase
                Analyse = []
                for analysis in range(
                    3, 6
                ):  # analyse le nombre de musiciens sur les phrases situées trois index plus bas, et quatre index après
                    Analyse.append(
                        Phrases_musicales_Index.count(
                            Phrases_musicales_Index[i] - analysis
                        )
                    )
#

print (Analyse)

                if (
                    Analyse.count(0) == 3
                ):  # s'il n'y en a plus, il peut passer au suivant
#

print(‘analyse ok’)

                    if (
                        random.randint(0, 100) < 60
                    ):  # Choix du musicien si il change de phrase musicale
                        Phrases_musicales_Index[i] = Phrases_musicales_Index[i] + 1
#

print ( ‘phrase musicale+1’)

            if (
                Phrases_musicales_Index[i] < 5
            ):  # Les cinq premières phrases ne risque pas d'aller trop vite
                if (
                    random.randint(0, 100) < 70
                ):  # % de chance pour le musicien de changer de phrase musicale
                    Phrases_musicales_Index[i] = Phrases_musicales_Index[i] + 1
#

print (Phrases_musicales_Index[i])